package org.jeecg.modules.demo.workflow.config.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.jeecg.modules.demo.bean.entity.WflowModelHistorys;
import org.jeecg.modules.demo.mapper.WflowModelHistorysMapper;
import org.jeecg.modules.demo.workflow.bean.dto.NotifyDto;
import org.jeecg.modules.demo.workflow.bean.process.OrgUser;
import org.jeecg.modules.demo.workflow.bean.process.props.ApprovalProps;
import org.jeecg.modules.demo.workflow.bean.vo.ProcessHandlerParamsVo;
import org.jeecg.modules.demo.workflow.config.WflowGlobalVarDef;
import org.jeecg.modules.demo.workflow.service.NotifyService;
import org.jeecg.modules.demo.workflow.service.UserDeptOrLeaderService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.runtime.ChangeActivityStateBuilder;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2022/8/23
 */
@Slf4j
@Component("userTaskListener")
public class UserTaskListener implements TaskListener, ExecutionListener {

    @Autowired
    private TaskService taskService;

    @Autowired
    private UserDeptOrLeaderService userService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private NotifyService notifyService;

    @Autowired
    private WflowModelHistorysMapper historysMapper;

    @Override
    public void notify(DelegateTask delegateTask) {
        //获取用户任务节点ID
        String nodeId = delegateTask.getTaskDefinitionKey();
        //assignment时间早于create触发，此时还没有创建成功task
        if ("create".equals(delegateTask.getEventName())) {
            //当任务被指派时，判断任务指派人是不是属于系统自动办理
            String assignee = delegateTask.getAssignee();
            if (WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(assignee)
                    || WflowGlobalVarDef.WFLOW_TASK_REFUSE.equals(assignee)) {
                boolean result = WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(assignee);
                Map<String, Object> var = new HashMap<>();
                var.put("approve_" + delegateTask.getId(),
                        result ? ProcessHandlerParamsVo.Action.agree : ProcessHandlerParamsVo.Action.refuse);
                taskService.complete(delegateTask.getId(), var);
                log.info("无审批人任务节点[{}]，交付系统控制[审批结果 {}]", nodeId, result);
            } else {
                processChangeNotify(delegateTask, false);
                log.info("实例[{}]的节点[{}]任务被指派给[{}]处理", delegateTask.getProcessInstanceId(), delegateTask.getTaskDefinitionKey(), assignee);
            }
        } else if ("complete".equals(delegateTask.getEventName())) {
            //当任务完成时，判断是不是驳回，驳回就执行驳回操作
            ProcessHandlerParamsVo.Action action = delegateTask.getVariable("approve_" + delegateTask.getId(), ProcessHandlerParamsVo.Action.class);
            //获取当前执行实例
            if (ProcessHandlerParamsVo.Action.refuse.equals(action)) {
                List<Execution> executions = runtimeService.createExecutionQuery()
                        .parentId(delegateTask.getProcessInstanceId())
                        .onlyChildExecutions().list();
                Map nodeProps = delegateTask.getVariable(WflowGlobalVarDef.WFLOW_NODE_PROPS, Map.class);
                ApprovalProps props = (ApprovalProps) nodeProps.get(nodeId);
                String target = "TO_NODE".equals(props.getRefuse().getType()) ? props.getRefuse().getTarget() : "refuse-end";
                //强制流程指向驳回/其他
                ChangeActivityStateBuilder builder = runtimeService.createChangeActivityStateBuilder()
                        .processInstanceId(delegateTask.getProcessInstanceId());
                if (executions.size() > 1) {
                    //多实例
                    builder.moveExecutionsToSingleActivityId(executions.stream().map(Execution::getId)
                            .collect(Collectors.toList()), target).changeState();
                } else {
                    builder.moveActivityIdTo(delegateTask.getTaskDefinitionKey(), target).changeState();
                }
                if ("TO_END".equals(props.getRefuse().getType())) {
                    processChangeNotify(delegateTask, true);
                }
            }
            log.info("任务[{} - {}]由[{}]完成", delegateTask.getTaskDefinitionKey(), delegateTask.getName(), delegateTask.getAssignee());
        }
    }

    @Override
    public void notify(DelegateExecution execution) {
        log.info("执行监听触发[活动:{}]", execution.getCurrentActivityId());
    }

    private void processChangeNotify(DelegateTask delegateTask, boolean isRefuse) {
        String instanceId = delegateTask.getProcessInstanceId();
        String dfId = delegateTask.getProcessDefinitionId();
        String startUser = String.valueOf(delegateTask.getVariable(WflowGlobalVarDef.INITIATOR));
        String assignee = delegateTask.getAssignee();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(instanceId).singleResult();
        String defName = "??";
        if (Objects.nonNull(processInstance)) {
            defName = processInstance.getProcessDefinitionName();
        } else {
            WflowModelHistorys modelHistory = historysMapper.selectOne(new LambdaQueryWrapper<WflowModelHistorys>()
                    .select(WflowModelHistorys::getFormName).eq(WflowModelHistorys::getProcessDefId, dfId));
            if (Objects.nonNull(modelHistory)) {
                defName = modelHistory.getFormName();
            }
        }
        System.out.println("startUser = " + startUser);
        OrgUser orgUser = userService.getUserMapByIds(CollectionUtil.newArrayList(startUser)).get(startUser);
        notifyService.notify(NotifyDto.builder()
                .title(isRefuse ? "您提交的审批被驳回" : "您有新的待办任务")
                .processDefId(dfId)
                .instanceId(instanceId)
                .nodeId(delegateTask.getTaskDefinitionKey())
                .target(isRefuse ? startUser : assignee)
                .content(isRefuse ? StrUtil.builder("您提交的【", defName, "】已被驳回").toString()
                        : StrUtil.builder(orgUser.getName(), " 提交的【", defName, "】需要您审批，请即时处理"
                ).toString())
                .type(isRefuse ? NotifyDto.TypeEnum.ERROR : NotifyDto.TypeEnum.WARNING)
                .build());
    }
}
